/*
 * This file is part of aKoustiK.

 * aKoustiK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * aKoustiK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with aKoustiK.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <KUrl>

#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtCore/QTime>
#include <QtCore/QXmlStreamReader>
#include <QtCore/QXmlStreamWriter>

#include <storage/xspfstorage.h>

XspfStorage::XspfStorage(const QString &targetFile) : filePath(targetFile) {
    qDebug("XspfStorage: constructor invoked");
}

XspfStorage::~XspfStorage() {
    qDebug("XspfStorage: destructor invoked");
}

void XspfStorage::store() {
    qDebug() << "XspfStorage: storing " << playlistItems.size() << " items into " << filePath;

    QFile file(filePath);
    if (!file.open(QFile::WriteOnly | QFile::Truncate)) {
        qDebug() << "XspfStorage: could not open file for writing, error: " << file.error();
        // TODO we should better show it to user
        return;
    }

    QXmlStreamWriter writer(&file);
    writer.setAutoFormatting(true);
    writer.writeStartDocument();
    writer.writeDefaultNamespace("http://xspf.org/ns/0/");
    writer.writeStartElement("playlist");
    writer.writeAttribute("version", "1");

    if (!playlistName.isNull() && !playlistName.isEmpty()) {
        writer.writeTextElement("title", playlistName);
    }

    writer.writeStartElement("trackList");

    if (!playlistItems.isEmpty()) {
        for (int i = 0; i < playlistItems.size(); i++) {
            writeItem(playlistItems.at(i), writer);
        }
    }

    writer.writeEndElement(); // trackList
    writer.writeEndElement(); // playlist
    writer.writeEndDocument();

    file.flush();
    file.close();

    qDebug("XspfStorage: storing done.");
}

void XspfStorage::load() {
    qDebug() << "XspfStorage: loading from " << filePath;

    // cleaning result fields:
    playlistName.clear();
    playlistItems.clear();

    QFile file(filePath);
    if (!file.open(QFile::ReadOnly)) {
        qDebug() << "XspfStorage: could not open file for reading, error: " << file.error();
        // TODO we should better show it to user
        return;
    }

    QXmlStreamReader reader(&file);

    if (reader.readNextStartElement()) {
        // plyalist should be first element:
        if (reader.name() == "playlist") {
            while (reader.readNextStartElement()) {
                if ("trackList" == reader.name()) {
                    //qDebug("XspfStorage: found trackList element...");
                    while (reader.readNextStartElement()) {
                        if ("track" == reader.name()) {
                            Item* item = readItem(reader);
                            if (item) {
                                playlistItems.append(item);
                            }
                            continue;
                        }
                        //qDebug() << "XspfStorage: skipping element: " << reader.name();
                        reader.skipCurrentElement();
                    }
                    continue;
                }
                if ("title" == reader.name()) {
                    //qDebug("XspfStorage: found title element...");
                    playlistName = reader.readElementText();
                    continue;
                }
                //qDebug() << "XspfStorage: skipping element: " << reader.name();
                reader.skipCurrentElement();
            }
        }
    }

    if (reader.hasError()) {
        qDebug() << "XspfStorage: error while parsing XML: " << reader.errorString();
    }

    file.close();

    qDebug("XspfStorage: loading of %i items done.", playlistItems.size());
}

void XspfStorage::writeItem(Item *item, QXmlStreamWriter &writer) {
    writer.writeStartElement("track");

    // TODO check the difference between URL and URI
    writer.writeTextElement("location", item->url().path());

    const QString& title = item->title();
    if (!title.isNull() && !title.isEmpty()) {
        writer.writeTextElement("title", title);
    }

    const QString& artist = item->artist();
    if (!artist.isNull() && !artist.isEmpty()) {
        writer.writeTextElement("creator", artist);
    }

    const QString& album = item->album();
    if (!album.isNull() && !album.isEmpty()) {
        writer.writeTextElement("album", album);
    }

    int durationSeconds = item->durationSeconds();
    if (durationSeconds > 0) {
        writer.writeTextElement("duration", QString::number(durationSeconds * 1000));
    }

    const QString& year = item->year();
    if (!year.isNull() && !year.isEmpty()) {
        writer.writeStartElement("meta");
        writer.writeAttribute("rel", "http://akoustik.googlecode.com/year");
        writer.writeCharacters(year);
        writer.writeEndElement();
    }

    writer.writeEndElement(); // track
}

Item* XspfStorage::readItem(QXmlStreamReader &reader) {
    qDebug("XspfStorage: reading Item...");
    if (!reader.isStartElement() || "track" != reader.name()) {
        qDebug("XspfStorage: readItem invoked in wrong element.");
        // it's wrong element!
        return 0;
    }

    Item* item = new Item();
    while (reader.readNextStartElement()) {
        //qDebug() << "XspfStorage: element found: " << reader.name();
        if ("location" == reader.name()) {
            // TODO check the difference between URL and URI
            item->setUrl(KUrl(reader.readElementText()));
            continue;
        }
        if ("title" == reader.name()) {
            item->setTitle(reader.readElementText());
            continue;
        }
        if ("creator" == reader.name()) {
            item->setArtist(reader.readElementText());
            continue;
        }
        if ("album" == reader.name()) {
            item->setAlbum(reader.readElementText());
            continue;
        }
        if ("meta" == reader.name() && reader.attributes().value("rel") == "http://akoustik.googlecode.com/year") {
            item->setYear(reader.readElementText());
            continue;
        }
        if ("duration" == reader.name()) {
            QString durationString = reader.readElementText();
            int durationSeconds = durationString.toInt() / 1000;
            item->setDurationSeconds(durationSeconds);
            QTime time(durationSeconds / 3600, (durationSeconds / 60) % 60, durationSeconds % 60);
            if (time.hour() > 0) {
                item->setDuration(time.toString("HH:mm:ss"));
            }
            else {
                item->setDuration(time.toString("mm:ss"));
            }
            continue;
        }
        // we do not handle this element, skip it:
        //qDebug() << "XspfStorage: skipping element: " << reader.name();
        reader.skipCurrentElement();
    }
    return item;
}

const QString& XspfStorage::name() const {
    return playlistName;
}

void XspfStorage::setName(const QString &value) {
    playlistName = value;
}

const QList<Item*> XspfStorage::items() const {
    return playlistItems;
}

void XspfStorage::setItems(const QList<Item *> &value) {
    playlistItems = value;
}
